#include "compiler/lexer.h"
#include <cctype>
#include <iostream>
#include <algorithm>

const std::unordered_map<std::string, TokenType> Lexer::keywords = {
    {"SELECT", TokenType::KEYWORD},
    {"FROM", TokenType::KEYWORD},
    {"WHERE", TokenType::KEYWORD},
    {"CREATE", TokenType::KEYWORD},
    {"TABLE", TokenType::KEYWORD},
    {"INSERT", TokenType::KEYWORD},
    {"INTO", TokenType::KEYWORD},
    {"VALUES", TokenType::KEYWORD},
    {"DELETE", TokenType::KEYWORD},
    {"UPDATE", TokenType::KEYWORD},
    {"SET", TokenType::KEYWORD},
    {"INT", TokenType::KEYWORD},
    {"VARCHAR", TokenType::KEYWORD},
    {"AND", TokenType::KEYWORD},
    {"OR", TokenType::KEYWORD},
    {"BETWEEN", TokenType::KEYWORD}
};

Lexer::Lexer(const std::string& input)
    : input(input), pos(0), line(1), column(1) {
}

std::vector<Token> Lexer::tokenize() {
    std::vector<Token> tokens;
    while (pos < input.size()) {
        skipWhitespace();
        if (pos >= input.size()) break;

        Token token = readNextToken();
        if (token.type != TokenType::END) {
            tokens.push_back(token);
        }
    }
    tokens.emplace_back(TokenType::END, "", line, column);
    return tokens;
}

char Lexer::peek() const {
    if (pos >= input.size()) return '\0';
    return input[pos];
}

char Lexer::advance() {
    if (pos >= input.size()) return '\0';
    char c = input[pos++];
    if (c == '\n') {
        line++;
        column = 1;
    }
    else {
        column++;
    }
    return c;
}

void Lexer::skipWhitespace() {
    while (pos < input.size()) {
        if (std::isspace(peek())) {
            // Skip whitespace characters
            advance();
        } else if (peek() == '-' && peek(1) == '-') {
            // Skip SQL single-line comments (starting with --)
            while (pos < input.size() && peek() != '\n') {
                advance();
            }
        } else {
            break;
        }
    }
}

char Lexer::peek(int offset) const {
    if (pos + offset >= input.size()) return '\0';
    return input[pos + offset];
}

Token Lexer::readNextToken() {
    char c = peek();
    if (std::isalpha(c) || c == '_') {
        return readIdentifier();
    }
    else if (std::isdigit(c)) {
        return readNumber();
    }
    else if (c == '\'') {
        return readString();
    }
    else if (std::ispunct(c)) {
        return readOperator();
    }

    // 为非法字符提供更详细的信息
    std::string charInfo;
    if (c == '\0') {
        charInfo = "end of input";
    } else if (std::isspace(c)) {
        if (c == '\n') charInfo = "newline";
        else if (c == '\t') charInfo = "tab";
        else if (c == '\r') charInfo = "carriage return";
        else charInfo = "whitespace";
    } else {
        charInfo = "'" + std::string(1, c) + "'";
    }
    throw LexerError("Unexpected character: " + charInfo, line, column);
}

Token Lexer::readNumber() {
    int startLine = line;
    int startCol = column;
    std::string value;

    while (std::isdigit(peek())) {
        value += advance();
    }

    return Token(TokenType::CONST_INT, value, startLine, startCol);
}

Token Lexer::readString() {
    int startLine = line;
    int startCol = column;
    std::string value;

    
    advance();

    while (peek() != '\'' && peek() != '\0') {
        value += advance();
    }

    if (peek() != '\'') {
        throw LexerError("Unclosed string literal", line, column);
    }

    
    advance();

    return Token(TokenType::CONST_STRING, value, startLine, startCol);
}

Token Lexer::readIdentifier() {
    int startLine = line;
    int startCol = column;
    std::string value;

    while (std::isalnum(peek()) || peek() == '_') {
        value += advance();
    }

    // 检查是否是关键字（忽略大小写）
    std::string upperValue = value;
    std::transform(upperValue.begin(), upperValue.end(), upperValue.begin(), ::toupper);
    auto it = keywords.find(upperValue);
    if (it != keywords.end()) {
        return Token(it->second, value, startLine, startCol);
    }

    return Token(TokenType::IDENTIFIER, value, startLine, startCol);
}

Token Lexer::readOperator() {
    int startLine = line;
    int startCol = column;
    std::string value;

    char c = advance();
    value += c;

 
    if (c == '(' || c == ')' || c == ',' || c == ';') {
        return Token(TokenType::DELIMITER, value, startLine, startCol);
    }


    if (c == '>' && peek() == '=') {
        value += advance();
    }
    else if (c == '<' && peek() == '=') {
        value += advance();
    }
    else if (c == '!' && peek() == '=') {
        value += advance();
    }
    else if (c == '=' && peek() == '=') {
        value += advance();
    }

    return Token(TokenType::OPERATOR, value, startLine, startCol);
}